import { useRef, useEffect } from "react";
import { getTargetElement } from "./get-target-element";
import { useUnmount } from "./use-unmount";

const depsAreSame = (oldDeps: any, deps: any): boolean => {
  if (oldDeps === deps) return true;
  for (let i = 0; i < oldDeps.length; i++) {
    if (!Object.is(oldDeps[i], deps[i])) return false;
  }
  return true;
};

const useEffectWithTarget = (effect: any, deps: any[], target: any): void => {
  const hasInitRef = useRef<boolean>(false);

  const lastElementRef = useRef<any[]>([]);
  const lastDepsRef = useRef<any[]>([]);

  const unLoadRef = useRef<any>();

  useEffect(() => {
    const targets = Array.isArray(target) ? target : [target];
    const els = targets.map((item) => getTargetElement(item));

    // init run
    if (!hasInitRef.current) {
      hasInitRef.current = true;
      lastElementRef.current = els;
      lastDepsRef.current = deps;

      unLoadRef.current = effect();
      return;
    }

    if (
      els.length !== lastElementRef.current.length ||
      !depsAreSame(els, lastElementRef.current) ||
      !depsAreSame(deps, lastDepsRef.current)
    ) {
      unLoadRef.current?.();

      lastElementRef.current = els;
      lastDepsRef.current = deps;
      unLoadRef.current = effect();
    }
  });

  useUnmount(() => {
    unLoadRef.current?.();
    // for react-refresh
    hasInitRef.current = false;
  });
};

export { useEffectWithTarget };
